package com.cya.lotterysystem.service.impl;

import com.cya.lotterysystem.common.errcode.ServiceErrorCodeConstans;
import com.cya.lotterysystem.common.exception.ServiceException;
import com.cya.lotterysystem.common.utils.JacksonUtil;
import com.cya.lotterysystem.common.utils.RedisUtil;
import com.cya.lotterysystem.controller.param.CreateActivityParam;
import com.cya.lotterysystem.controller.param.CreatePrizeByActivityParam;
import com.cya.lotterysystem.controller.param.CreateUserByActivityParam;
import com.cya.lotterysystem.controller.param.PageParam;
import com.cya.lotterysystem.dao.mapper.ActivityMapper;
import com.cya.lotterysystem.dao.dataobject.ActivityDO;
import com.cya.lotterysystem.dao.dataobject.PrizeDO;
import com.cya.lotterysystem.dao.mapper.ActivityPrizeMapper;
import com.cya.lotterysystem.dao.mapper.ActivityUserMapper;
import com.cya.lotterysystem.dao.mapper.PrizeMapper;
import com.cya.lotterysystem.dao.mapper.UserMapper;
import com.cya.lotterysystem.service.ActivityService;
import com.cya.lotterysystem.service.dto.*;
import com.cya.lotterysystem.service.enums.ActivityPrizeStatusEnum;
import com.cya.lotterysystem.service.enums.ActivityPrizeTiersEnum;
import com.cya.lotterysystem.service.enums.ActivityStatusEnum;
import com.cya.lotterysystem.service.enums.ActivityUserStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author ：陈奕安（3048279304@qq.com）
 * @date ：Created in 2025/11/3 16:08
 * @description：
 * @modified By：
 * @version:
 */
@Slf4j
@Service
public class ActivityServiceImpl implements ActivityService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private PrizeMapper prizeMapper;

    @Autowired
    private ActivityMapper activityMapper;

    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;

    @Autowired
    private ActivityUserMapper activityUserMapper;

    @Autowired
    private RedisUtil redisUtil;
    /**
     * 活动缓存前缀
     */
    private final String ACTIVITY_PREFIX="ACTIVITY_";
    /**
     * 活动缓存时间
     */
    private final  Long ACTIVITY_TIMEOUT=60*60*24*3l;


    @Transactional(rollbackFor = Exception.class)//涉及多表
    @Override
    public CreateActivityDTO CreateActivity(CreateActivityParam param) {
//        校验活动信息是否正确
        checkActivityInfo(param);

//保存活动信息
        ActivityDO  activityDO=new ActivityDO();
        activityDO.setActivityName(param.getActivityName());
        activityDO.setDescription(param.getDescription());
        activityDO.setStatus(ActivityStatusEnum.RUNNING.name());
        activityMapper.insrt(activityDO);






//        保存活动关联的奖品信息
        List<CreatePrizeByActivityParam> prizeParams = param.getActivityPrizeList();
        List<ActivityPrizeDO> activityPrizeDOList=prizeParams.stream()
                .map(prizeParam->{
                    ActivityPrizeDO activityPrizeDO=new ActivityPrizeDO();
                    activityPrizeDO.setActivityId(activityDO.getId());
                    activityPrizeDO.setPrizeId(prizeParam.getPrizeId());
                    activityPrizeDO.setPrizeAmount(prizeParam.getPrizeAmount());
                    activityPrizeDO.setPrizeTiers(prizeParam.getPrizeTiers());
                    activityPrizeDO.setStatus(ActivityPrizeStatusEnum.INIT.name());

                    return activityPrizeDO;


                }).collect(Collectors.toList());
        activityPrizeMapper.batchInsert(activityPrizeDOList);
//        保存活动关联人员信息
        List<CreateUserByActivityParam> userParams=param.getActivityUserList();
            List<ActivityUserDO> activityUserDOList=userParams.stream()
                    .map(userParam->{
                        ActivityUserDO activityUserDO=new ActivityUserDO();
                        activityUserDO.setActivityId(activityDO.getId());
                        activityUserDO.setUserId(userParam.getUserId());
                        activityUserDO.setUserName(userParam.getUserName());
                        activityUserDO.setStatus(ActivityUserStatusEnum.INIT.name());
                        return activityUserDO;
                    }).collect(Collectors.toList());
            activityUserMapper.batchInsert(activityUserDOList);

//        整合完整的活动信息.存放到redis
// activityId: ActivityDetailDTO：包含活动+奖品+人员
//        需要先获取奖品基本属性列表
//        需要查询的奖品id
      List<Long> prizeIds=  param.getActivityPrizeList().stream()
                .map(CreatePrizeByActivityParam::getPrizeId)
                .distinct()
                .collect(Collectors.toList());
        List<PrizeDO> prizeDOList=prizeMapper.batchSelectByIds(prizeIds);

        ActivityDetailDTO detailDTO = converToActivityDetailDTO(activityDO, activityUserDOList, prizeDOList, activityPrizeDOList);

        cachaActivity(detailDTO);

//        构造返回

CreateActivityDTO createActivityDTO=new CreateActivityDTO();
createActivityDTO.setActivityId(activityDO.getId());
return createActivityDTO;



    }

    /**
     * 翻页查询活动摘要列表
     * @param param
     * @return
     */
    @Override
    public PageListDTO<ActivityDTO> findActivityList(PageParam param) {

//         获取总量
        int total=activityMapper.count();

//        获取当前列表
        List<ActivityDO> activityDOList=activityMapper.selectByActivityList(param.offset(),param.getPageSize());

        List<ActivityDTO> activityDTOList=activityDOList.stream()
                .map(activityDO -> {
                    ActivityDTO activityDTO=new ActivityDTO();
                    activityDTO.setActivityId(activityDO.getId());
                    activityDTO.setActivityName(activityDO.getActivityName());
                    activityDTO.setDescription(activityDO.getDescription());
                    activityDTO.setStatus(ActivityStatusEnum.forName(activityDO.getStatus()));
                        return activityDTO;
                }).collect(Collectors.toList());
        return new PageListDTO<>(total,activityDTOList);
    }

    @Override
    public ActivityDetailDTO getActivityDetail(Long activityId) {

        if (activityId==null){
            log.warn("查询活动详细信息失败，activityId为空！");
            return null;
        }
//        查询redis
        ActivityDetailDTO detailDTO = getActivityFromCache(activityId);
        if(detailDTO!=null){
            log.info("查询活动详细信息成功！detailDTO={}",JacksonUtil.writeValueAsString(detailDTO));
            return detailDTO;
        }

//       如果redis不存在该数据，查数据库
//        活动表
        ActivityDO aDO= activityMapper.selectById(activityId);


//        活动奖品表
        List<ActivityPrizeDO> apOList =activityPrizeMapper.selectByActivityId(activityId);

//        活动人员表
        List<ActivityUserDO> auDOList=activityUserMapper.selectByActivityId(activityId);
//        奖品表

        List<Long> prizeIds=    apOList.stream().
                map(ActivityPrizeDO::getPrizeId)
                .collect(Collectors.toList());

        List<PrizeDO> pdoList = prizeMapper.batchSelectByIds(prizeIds);

//        整合信息放到redis

        detailDTO=      converToActivityDetailDTO(aDO,auDOList,pdoList,apOList);
        cachaActivity(detailDTO);
//        返回
        return detailDTO;
    }

    @Override
    public void cacheActivity(Long activityId) {
        if (activityId==null){
            throw new ServiceException(ServiceErrorCodeConstans.CACHE_ACTIVITY_ID_IS_EMPTY);

        }

        //查询表数据，活动表，关联奖品，关联人员，奖品信息表
        ActivityDO aDO= activityMapper.selectById(activityId);
if (aDO==null){
    log.warn("要缓存的活动id为空!");
    throw new ServiceException(ServiceErrorCodeConstans.CACHE_ACTIVITY_ID_IS_ERROE);
}

//        活动奖品表
        List<ActivityPrizeDO> apOList =activityPrizeMapper.selectByActivityId(activityId);


//        活动人员表
        List<ActivityUserDO> auDOList=activityUserMapper.selectByActivityId(activityId);
//        奖品表

        List<Long> prizeIds=    apOList.stream().
                map(ActivityPrizeDO::getPrizeId)
                .collect(Collectors.toList());

        List<PrizeDO> pdoList = prizeMapper.batchSelectByIds(prizeIds);

//        整合信息放到redis

        cachaActivity(
                converToActivityDetailDTO(aDO,
                auDOList,
                pdoList,
                apOList));
    }

    /**
     * 缓存完整的活动信息 ActivityDetailDTO
     * @param detailDTO
     */
    private void cachaActivity(ActivityDetailDTO detailDTO) {
//        key :ACTIVITY_12
//        value:ActivityDetailDTO(json)
        if (detailDTO==null||detailDTO.getActivityId()==null){
            log.warn("要缓存的活动信息不存在!");
            return;
        }
        //缓存到redis

        try {
            redisUtil.set(ACTIVITY_PREFIX+detailDTO.getActivityId(),
                    JacksonUtil.writeValueAsString(detailDTO),
                    ACTIVITY_TIMEOUT);
        }catch (Exception e){
            log.error("缓存活动异常 ActivityDetailDTO：{}",JacksonUtil.writeValueAsString(detailDTO),e);
        }




    }

    /**
     * 根据活动id从缓存中获取活动信息
     * @param activityId
     * @return
     */
    private ActivityDetailDTO getActivityFromCache(Long activityId){

        if (null==activityId){
            log.warn("从缓存中获取活动数据的acticityId为空");
            return null;
        }
       try {
           String str=redisUtil.get(ACTIVITY_PREFIX+activityId);
           if (!StringUtils.hasText(str)){
               log.info("获取缓存数据为空：key={}0",str);
               return null;
           }
           ActivityDetailDTO detailDTO = JacksonUtil.readValue(str, ActivityDetailDTO.class);
           return detailDTO;
       }catch (Exception e){
           log.error("从缓存中获取活动信息异常：activityId：{}",activityId,e);
           return null;
       }
    }

    /**
     * 根据基本do转换完整的ActivityDetailDTO信息
     * @param activityDO
     * @param activityUserDOList
     * @param prizeDOList
     * @param activityPrizeDOList
     * @return
     */
    private ActivityDetailDTO converToActivityDetailDTO(ActivityDO activityDO,
                                           List<ActivityUserDO> activityUserDOList,
                                           List<PrizeDO> prizeDOList,
                                           List<ActivityPrizeDO> activityPrizeDOList) {
        ActivityDetailDTO detailDTO=new ActivityDetailDTO();
        detailDTO.setActivityId(activityDO.getId());
        detailDTO.setActivityName(activityDO.getActivityName());
        detailDTO.setDesc(activityDO.getDescription());
        detailDTO.setStatus(ActivityStatusEnum.forName(activityDO.getStatus()));
//        apdo:{prizeId,amount,ststus}
//        pDO:{prizeId,name}
        List<ActivityDetailDTO.PrizeDTO> prizeDTOList=activityPrizeDOList.stream()
                        .map(apDO -> {
                            ActivityDetailDTO.PrizeDTO prizeDTO=new ActivityDetailDTO.PrizeDTO();
                            prizeDTO.setPrizeId(apDO.getPrizeId());
//                            解决空指针异常
                        Optional<PrizeDO> optionalPrizeDO= prizeDOList.stream().filter(
                                    prizeDO -> prizeDO.getId().equals(apDO.getPrizeId()))
                                    .findFirst();

//                        如果prizedo为空，不执行当前方法
//                            不为空才执行
                                optionalPrizeDO.ifPresent(prizeDO -> {
                                    prizeDTO.setName(prizeDO.getName());
                                    prizeDTO.setDescription(prizeDO.getDescription());
                                    prizeDTO.setImageUrl(prizeDO.getImageUrl());
                                    prizeDTO.setPrice(prizeDO.getPrice());
                                });

                            prizeDTO.setTiers(ActivityPrizeTiersEnum.forName(apDO.getPrizeTiers()));
                            prizeDTO.setPrizeAmount(apDO.getPrizeAmount());
                            prizeDTO.setStatus(ActivityPrizeStatusEnum.forName(apDO.getStatus()));
                        return prizeDTO;

                        }).collect(Collectors.toList());


        detailDTO.setPrizeDTOList(prizeDTOList);
      List<ActivityDetailDTO.UserDTO> userDTOList=  activityUserDOList.stream()
                        .map(audo->{
                            ActivityDetailDTO.UserDTO userDTO=new ActivityDetailDTO.UserDTO();
                            userDTO.setUserId(audo.getUserId());
                            userDTO.setUserName(audo.getUserName());
                            userDTO.setStatus(ActivityUserStatusEnum.forName(audo.getStatus()));
                            return userDTO;

                        }).collect(Collectors.toList());
        detailDTO.setUserDTOList(userDTOList);

        return detailDTO;
    }

    /**
     * 校验活动有效性
     * @param param
     */
    private void checkActivityInfo(CreateActivityParam param){
        if (null==param){
            throw new ServiceException(ServiceErrorCodeConstans.CREATE_ACTIVITY_INFO_IS_EMPTY);
        }
//        校验人员id在人员表中存在
        List<Long> userIds=param.getActivityUserList().stream()
                .map(CreateUserByActivityParam::getUserId)
                .distinct()//去重
                .collect(Collectors.toList());

        List<Long> existUserIds = userMapper.selectExistByIds(userIds);
if (CollectionUtils.isEmpty(existUserIds)){
    throw new ServiceException(ServiceErrorCodeConstans.ACTIVITY_USER_ERROR);
}
        userIds.forEach(id->{
            if (!existUserIds.contains(id)){
                throw new ServiceException(ServiceErrorCodeConstans.ACTIVITY_USER_ERROR);

            }

        });

//        校验奖品id在奖品表中是否存在
            List<Long> prizeIds=param.getActivityPrizeList().stream()
                    .map(CreatePrizeByActivityParam::getPrizeId)
                    .distinct()
                    .collect(Collectors.toList());
            List<Long> existPrizeIds=prizeMapper.selectExistByIds(prizeIds);
       if  (CollectionUtils.isEmpty(existPrizeIds)){
            throw new ServiceException(ServiceErrorCodeConstans.ACTIVITY_USER_ERROR);

        }
            prizeIds.forEach(ids->{
                if (!existPrizeIds.contains(ids)){
                    throw new ServiceException(ServiceErrorCodeConstans.ACTIVITY_PRIZE_ERROR);
                }
            });

//        人员数量大于等于奖品数量

        int userAmount=param.getActivityUserList().size();

        long prizeAmount=param.getActivityPrizeList().stream()
                .mapToLong(CreatePrizeByActivityParam::getPrizeAmount)
                .sum();
        if (userAmount<prizeAmount){
            throw new ServiceException(ServiceErrorCodeConstans.USER_PRIZE_AMOUNT_ERROR);
        }

//        校验活动奖品等级有效性
        param.getActivityPrizeList().forEach(prize->{
            if (null==ActivityPrizeTiersEnum.forName(prize.getPrizeTiers())){
                throw new ServiceException(ServiceErrorCodeConstans.ACTIVITY_PRIZE_TIERS_ERROR);
            }
        });
    }
}